package com.linktel.productionLine.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.linktel.productionLine.EasyExcel.dailyAttendance.model.WriteDailyAttendance;
import com.linktel.productionLine.common.ErrorCode;
import com.linktel.productionLine.dao.DailyAttendanceDao;
import com.linktel.productionLine.dao.MonthlyPlanningDao;
import com.linktel.productionLine.dao.WorklineDailyActualEfficiencyDao;
import com.linktel.productionLine.entity.ProductionLine;
import com.linktel.productionLine.entity.dto.dailyAttendance.AttendanceInfoDTO;
import com.linktel.productionLine.entity.query.dailyAttendance.AddAttendanceInfoQuery;
import com.linktel.productionLine.entity.query.dailyAttendance.DeleteAttendanceInfoQuery;
import com.linktel.productionLine.entity.query.dailyAttendance.EditAttendanceInfoQuery;
import com.linktel.productionLine.entity.query.dailyAttendance.ListAttendanceInfoQuery;
import com.linktel.productionLine.exception.BusinessException;
import com.linktel.productionLine.util.MethodUtils;
import io.swagger.models.auth.In;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Month;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author HuangJiaHui
 * @Date 2023/9/3 16:53
 */
@Service
@AllArgsConstructor
public class DailyAttendanceService {

    private DailyAttendanceDao dailyAttendanceDao;

    private MonthlyPlanningDao monthlyPlanningDao;

    private WorklineDailyActualEfficiencyDao worklineDailyActualEfficiencyDao;

    private ProductionLineService productionLineService;

    /**
     * 根据封装对象筛选查询，展示产线的日出勤基础数据
     *
     * @param listAttendanceInfoQuery 用户id
     * @return 日出勤数据列表
     */
    public PageInfo<AttendanceInfoDTO> listAttendanceInfo(ListAttendanceInfoQuery listAttendanceInfoQuery) {
        String productionLineCode = listAttendanceInfoQuery.getProductionLineCode();
        String attendanceDate = listAttendanceInfoQuery.getAttendanceDate();
        Long commitUserId = listAttendanceInfoQuery.getCommitUserId();
        int pageNum = listAttendanceInfoQuery.getPageNum();
        int pageSize = listAttendanceInfoQuery.getPageSize();
        if (commitUserId == null || commitUserId <= 0 || pageNum <= 0 || pageSize <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "填写数据不完整，请重新填写");
        }
        Integer year = null;
        Integer month = null;
        if (attendanceDate != null && !"".equals(attendanceDate)) {
            Calendar calendar = MethodUtils.getCalendarByDate(attendanceDate);
            year = calendar.get(Calendar.YEAR);
            month = calendar.get(Calendar.MONTH) + 1;
        }
        PageHelper.startPage(pageNum,pageSize);
        List<AttendanceInfoDTO> result = dailyAttendanceDao.listAttendanceInfo(productionLineCode, year, month);
        return new PageInfo<>(result);


    }

    /**
     * 新增日出勤基础数据
     * 一条产线、同一天只能有一条日出勤基础数据
     *
     * @param addAttendanceInfoQuery 新增日出勤基础数据的封装对象
     * @return 是否新增成功
     */
    public Boolean addAttendanceInfo(AddAttendanceInfoQuery addAttendanceInfoQuery) {
        String productionLineCode = addAttendanceInfoQuery.getProductionLineCode();
        LocalDate attendanceDate = addAttendanceInfoQuery.getAttendanceDate();
        Integer workTime = addAttendanceInfoQuery.getWorkTime();
        Integer planningNumber = addAttendanceInfoQuery.getPlanningNumber();
        Integer actualNumber = addAttendanceInfoQuery.getActualNumber();
        Long currentUserId = addAttendanceInfoQuery.getCurrentUserId();
        Double targetEfficiency = addAttendanceInfoQuery.getTargetEfficiency();
        if (productionLineCode == null || currentUserId == null || currentUserId <= 0 || attendanceDate == null || workTime == null || planningNumber == null || actualNumber == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "填写数据不完整，请重新填写");
        }
        List<Long> dailyAttendanceIds = dailyAttendanceDao.getDailyAttendance(productionLineCode, attendanceDate.toString(), currentUserId);
        if (dailyAttendanceIds != null && dailyAttendanceIds.size() >= 1) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "一条产线、同一天只能有一条日出勤基础数据，不能重复添加");
        }

//        saveNullEfficiencyData(productionLineCode, attendanceDate);

        return dailyAttendanceDao.addAttendanceInfo(productionLineCode, attendanceDate, workTime, planningNumber, actualNumber, targetEfficiency, currentUserId);
    }

    public void saveNullEfficiencyData(String productionLineCode, LocalDate attendanceDate) {
        // 如果在work_line_daily_actual_efficiency表中存在该年、月数据并且数量小于当前月份天数，就把该月数据补全
        int year = attendanceDate.getYear();
        int month = attendanceDate.getMonth().getValue();
        Set<String> quantityByYearAndMonth = worklineDailyActualEfficiencyDao.getStatisticsDateByYearAndMonth(productionLineCode, year, month);
        // 该月天数
        List<String> localDateList = this.getDateByMonth(year, month);
        int quantity = localDateList.size();
        if (quantityByYearAndMonth.size() > 0 && quantity > quantityByYearAndMonth.size()) {
            // 补全该月数据
            ProductionLine productionLine = productionLineService.getByCode(productionLineCode);
            Long productionLineId = productionLine.getId();
            String productionLineName = productionLine.getName();

            List<String> localDateFinalList = localDateList.stream().filter(item -> !quantityByYearAndMonth.contains(item)).collect(Collectors.toList());

            worklineDailyActualEfficiencyDao.saveNullDataByYearAndMonth(productionLineId, productionLineCode, productionLineName, year, month, localDateFinalList);
        }
    }

    /**
     * 修改日出勤基础数据
     * 一条产线、同一天只能有一条日出勤基础数据
     *
     * @param editAttendanceInfoQuery 修改日出勤基础数据的封装对象
     * @return 是否修改成功
     */
    @Transactional
    public Boolean editAttendanceInfo(EditAttendanceInfoQuery editAttendanceInfoQuery) {
        Long id = editAttendanceInfoQuery.getId();
        LocalDate attendanceDate = editAttendanceInfoQuery.getAttendanceDate();
        Integer workTime = editAttendanceInfoQuery.getWorkTime();
        Integer planningNumber = editAttendanceInfoQuery.getPlanningNumber();
        Integer actualNumber = editAttendanceInfoQuery.getActualNumber();
        Long currentUserId = editAttendanceInfoQuery.getCurrentUserId();
        String productionLineCode = editAttendanceInfoQuery.getProductionLineCode();
        Double targetEfficiency = editAttendanceInfoQuery.getTargetEfficiency();
        if (id == null || id <= 0 || currentUserId == null || currentUserId <= 0 || attendanceDate == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "填写数据不完整");
        }
        Boolean result = dailyAttendanceDao.editAttendanceInfo(id, attendanceDate, workTime, planningNumber, actualNumber, targetEfficiency, currentUserId);
        List<Long> dailyAttendanceIds = dailyAttendanceDao.getDailyAttendance(productionLineCode, attendanceDate.toString(), currentUserId);
        if (dailyAttendanceIds != null && dailyAttendanceIds.size() >= 2) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "一条产线、同一天只能有一条日出勤基础数据，不能重复");
        }
        return result;
    }

    /**
     * 删除日出勤基础数据
     *
     * @param deleteAttendanceInfoQuery 删除日出勤基础数据的封装对象
     * @return 是否删除成功
     */
    public Boolean deleteAttendanceInfo(DeleteAttendanceInfoQuery deleteAttendanceInfoQuery) {
        Long id = deleteAttendanceInfoQuery.getId();
        Long currentUserId = deleteAttendanceInfoQuery.getCurrentUserId();
        if (id == null || id <= 0 || currentUserId == null || currentUserId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        return dailyAttendanceDao.deleteAttendanceInfo(id, currentUserId);
    }

    /**
     * 根据封装对象筛选查询，返回产线的日出勤基础数据，用WriteDailyAttendance对象封装
     *
     * @param listAttendanceInfoQuery 筛选查询出勤数据的封装对象
     * @return WriteDailyAttendance对象列表
     */
    public List<WriteDailyAttendance> downloadAttendanceDate(ListAttendanceInfoQuery listAttendanceInfoQuery) {
        Long commitUserId = listAttendanceInfoQuery.getCommitUserId();
        if (commitUserId == null || commitUserId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "填写数据不完整，请重新填写");
        }
        String productionLineCode = listAttendanceInfoQuery.getProductionLineCode();
        String attendanceDate = listAttendanceInfoQuery.getAttendanceDate();
        Integer year = null;
        Integer month = null;
        if (attendanceDate != null && !"".equals(attendanceDate)) {
            Calendar calendar = MethodUtils.getCalendarByDate(attendanceDate);
            year = calendar.get(Calendar.YEAR);
            month = calendar.get(Calendar.MONTH) + 1;
        }

        List<AttendanceInfoDTO> attendanceInfoDTOList = dailyAttendanceDao.listAttendanceInfo(productionLineCode, year, month);
        return attendanceInfoDTOList.stream().map(item -> {
            WriteDailyAttendance writeDailyAttendance = new WriteDailyAttendance();
            BeanUtils.copyProperties(item, writeDailyAttendance);
            writeDailyAttendance.setAttendanceDate(item.getAttendanceDate().toString());
            return writeDailyAttendance;
        }).collect(Collectors.toList());
    }

    /**
     * 获取该年月的所有日期集合
     *
     * @param year 年
     * @param month 月
     * @return 日期集合
     */
    private List<String> getDateByMonth(int year, int month) {
        SimpleDateFormat dateFormatYYYYMMDD = new SimpleDateFormat("yyyy-MM-dd");
        List<String> fullDayList = new ArrayList<>(32);
        // 获得当前日期对象
        Calendar cal = Calendar.getInstance();
        cal.clear();// 清除信息
        cal.set(Calendar.YEAR, year);
        // 1月从0开始
        cal.set(Calendar.MONTH, month-1 );
        // 当月1号
        cal.set(Calendar.DAY_OF_MONTH,1);
        int count = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        for (int j = 1; j <= count ; j++) {
            fullDayList.add(dateFormatYYYYMMDD.format(cal.getTime()));
            cal.add(Calendar.DAY_OF_MONTH,1);
        }
        return fullDayList;
    }
}
